package keter.ssh.core;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import java.util.Properties;

import keter.framework.util.IOUtil;
import keter.ssh.model.Host;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.base.Strings;
import com.jcraft.jsch.ChannelExec;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import com.jcraft.jsch.SftpException;

public class SshUtil {

	private ChannelSftp channelSftp;
	private ChannelExec channelExec;
	private Session session = null;
	private static int timeout = 5000;
	
	public static void setTimeout(int timeout) {
		SshUtil.timeout = timeout;
	}

	private boolean error = false;
	public boolean hasError() {
		return error;
	}

	private String result = "";
	public String result() {
		return result;
	}
	
	private Host host;
	
	public Host getHost() {
		return host;
	}

	private static final Logger logger = LoggerFactory.getLogger(SshUtil.class);
 
	
	public static  SshUtil init(Host host) throws Exception{
		return new SshUtil(host);
	}
	
	public static  SshUtil init(Host host,int timeout) throws Exception{
		SshUtil.setTimeout(timeout);
		return new SshUtil(host);
	}
	
	public SshUtil(Host host) throws Exception {
		this.host = host;
		logger.info("尝试连接到主机 {} ...",host.getAddr());
		logger.info("username:{},password:{}",host.getUsername(),host.getPassword());
		JSch jsch = new JSch(); // 创建JSch对象
		session = jsch.getSession(host.getUsername(), host.getAddr(),
				host.getPort()); // 根据用户名，主机ip，端口获取一个Session对象
		session.setPassword(host.getPassword()); // 设置密码
		Properties config = new Properties();
		config.put("StrictHostKeyChecking", "no");
		session.setConfig(config); // 为Session对象设置properties
		session.setTimeout(timeout); // 设置timeout时间
		session.connect(); // 通过Session建立链接
		logger.info("主机 {} 连接成功!",host.getAddr());
	}

	public void download(String src, String dst) throws Exception {
		channelSftp = (ChannelSftp) session.openChannel("sftp");
		channelSftp.connect();
		channelSftp.get(src, dst);
		channelSftp.quit();
	}

	public void uploadBatch(String src, String dst) throws Exception {
		push(src, dst);
	}
	
	public void upload(String src, String dst) throws Exception {
		push(src, dst);
//		close();
	}

	private void push(String src, String dst) throws JSchException,
			SftpException, IOException {
		channelSftp = (ChannelSftp) session.openChannel("sftp");
		channelSftp.connect();
//		logger.info("文件传输准备:源文件-[{}]，目标文件-[{}]",src,dst);
		channelSftp.put(src, dst,
				new FileProgressMonitor(IOUtil.sizeOf(src)),
				ChannelSftp.OVERWRITE);
		channelSftp.quit();
	}
	

	
	public SshUtil exec(String cmd, String charset) throws JSchException, IOException{
		runCommand(cmd, charset);
		return this;
	}
	
	public SshUtil exec(String cmd) throws Exception {
		return exec(cmd, "UTF-8");
	}
	
	public SshUtil execOnce(String cmd, String charset) throws JSchException, IOException{
		runCommand(cmd, charset);
		close();
		return this;
	}
	
	public SshUtil execOnce(String cmd) throws Exception {
		return execOnce(cmd, "UTF-8");
	}
	


	private void runCommand(String cmd, String charset) throws JSchException,
			IOException {
		String errorMsg = "";
		channelExec = (ChannelExec) session.openChannel("exec");
		channelExec.setCommand(cmd);
		channelExec.setInputStream(null);
		channelExec.setErrStream(System.err);
		channelExec.connect();
		InputStream in = channelExec.getInputStream();
		//必须先声明，否则流一旦读完就无法重复读取
		InputStream stderr = channelExec.getErrStream();
		result = getResultFromStream(in,charset);
		errorMsg =  getResultFromStream(stderr,charset);	
		channelExec.disconnect();
		if(!Strings.isNullOrEmpty(errorMsg)){
			logger.error("command [{}], error:\n{}",cmd,error);
			error = true;
			result = errorMsg;
		}
	}
	
	private String getResultFromStream(InputStream in,String charset) throws IOException{
		String result="";
		BufferedReader reader = new BufferedReader(new InputStreamReader(in,
				Charset.forName(charset)));
		String buf = null;
		while ((buf = reader.readLine()) != null) {
			result += buf+"\n";
		}
		reader.close();
		return result;
	}

	public void close() {
		if(session!=null || session.isConnected()){
			session.disconnect();
		}
	}
}